bitkeeper revision 1.1082 (40f5427bJQEFqTSPn7NWKEkiQ-CC9g)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 14 Jul 2004 14:26:03 +0000 (14:26 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 14 Jul 2004 14:26:03 +0000 (14:26 +0000)
Allow loading of kernel images with virtual-memory base different
from kernel-image load base.

linux-2.4.26-xen-sparse/arch/xen/kernel/head.S
linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c
linux-2.4.26-xen-sparse/arch/xen/vmlinux.lds
tools/libxc/xc_linux_build.c
xen/arch/x86/domain.c
xen/common/elf.c
xen/include/xen/elf.h

index 2d9379a15b73d3eec1092eaaeffb0405bc7a3cad..cf5aa93fce3c1b3f412b022abc986c416f3e1718 100644 (file)
@@ -1,6 +1,6 @@
 
 .section __xen_guest
-    .asciz "GUEST_OS=linux,GUEST_VER=2.4,XEN_VER=1.3"
+    .asciz "GUEST_OS=linux,GUEST_VER=2.4,XEN_VER=1.3,VIRT_BASE=0xC0000000"
 
 .text
 #include <linux/config.h>
index 42ef543546d3138f0e5e12c0b30a664c4c616d9e..039fdaf1624b0b0e90b8d4b9bbf9afa8ef139428 100644 (file)
@@ -205,6 +205,8 @@ void __init setup_arch(char **cmdline_p)
     extern const struct exception_table_entry __start___ex_table[];
     extern const struct exception_table_entry __stop___ex_table[];
 
+    extern char _stext;
+
     /* Force a quick death if the kernel panics. */
     extern int panic_timeout;
     if ( panic_timeout == 0 )
@@ -314,7 +316,9 @@ void __init setup_arch(char **cmdline_p)
      */
     bootmap_size = init_bootmem(start_pfn, max_low_pfn);
     free_bootmem(0, PFN_PHYS(max_low_pfn));
-    reserve_bootmem(0, PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE-1);
+    reserve_bootmem(__pa(&_stext), 
+                    PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE-1 - 
+                    __pa(&_stext));
 
 #ifdef CONFIG_BLK_DEV_INITRD
     if ( start_info.mod_start != 0 )
index 6bd3ec3c04894119d1354b8aaabd4da5b49fefc1..258de1a67f4ec011a64b331fbeceebb6153b31d7 100644 (file)
@@ -6,7 +6,7 @@ OUTPUT_ARCH(i386)
 ENTRY(_start)
 SECTIONS
 {
-  . = 0xC0000000 + 0x000000;
+  . = 0xC0000000 + 0x100000;
   _text = .;                   /* Text and read-only data */
   .text : {
        *(.text)
index c2228b5e9ea26fa19b7007d64b8f30acdb63f66c..e2edd81e170dd3231bbdb4818a0a5b1a30bd5913 100644 (file)
@@ -5,6 +5,7 @@
 #include "xc_private.h"
 #define ELFSIZE 32
 #include "xc_elf.h"
+#include <stdlib.h>
 #include <zlib.h>
 
 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
 #define round_pgup(_p)    (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
 #define round_pgdown(_p)  ((_p)&PAGE_MASK)
 
-static int readelfimage_base_and_size(char *elfbase, 
-                                      unsigned long elfsize,
-                                      unsigned long *pkernstart,
-                                      unsigned long *pkernend,
-                                      unsigned long *pkernentry);
+static int parseelfimage(char *elfbase, 
+                         unsigned long elfsize,
+                         unsigned long *pvirtstart,
+                         unsigned long *pkernstart,
+                         unsigned long *pkernend,
+                         unsigned long *pkernentry);
 static int loadelfimage(char *elfbase, void *pmh, unsigned long *parray,
                         unsigned long vstart);
 
@@ -109,11 +111,17 @@ static int setup_guestos(int xc_handle,
     unsigned long vpt_end;
     unsigned long v_end;
 
-    rc = readelfimage_base_and_size(image, image_size, 
-                                    &vkern_start, &vkern_end, &vkern_entry);
+    rc = parseelfimage(image, image_size, &v_start,
+                       &vkern_start, &vkern_end, &vkern_entry);
     if ( rc != 0 )
         goto error_out;
     
+    if ( (v_start & (PAGE_SIZE-1)) != 0 )
+    {
+        PERROR("Guest OS must load to a page boundary.\n");
+        goto error_out;
+    }
+
     /*
      * Why do we need this? The number of page-table frames depends on the 
      * size of the bootstrap address space. But the size of the address space 
@@ -123,7 +131,6 @@ static int setup_guestos(int xc_handle,
      */
     for ( nr_pt_pages = 2; ; nr_pt_pages++ )
     {
-        v_start          = vkern_start & ~((1<<22)-1);
         vinitrd_start    = round_pgup(vkern_end);
         vinitrd_end      = vinitrd_start + initrd_len;
         vphysmap_start   = round_pgup(vinitrd_end);
@@ -137,18 +144,11 @@ static int setup_guestos(int xc_handle,
         v_end            = (vstack_end + (1<<22)-1) & ~((1<<22)-1);
         if ( (v_end - vstack_end) < (512 << 10) )
             v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */
-        if ( (((v_end - v_start) >> L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
+        if ( (((v_end - v_start + ((1<<L2_PAGETABLE_SHIFT)-1)) >> 
+               L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
             break;
     }
 
-    if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) )
-    {
-        printf("Initial guest OS requires too much space\n"
-               "(%luMB is greater than %luMB limit)\n",
-               (v_end-v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
-        goto error_out;
-    }
-
     printf("VIRTUAL MEMORY ARRANGEMENT:\n"
            " Loaded kernel: %08lx->%08lx\n"
            " Init. ramdisk: %08lx->%08lx\n"
@@ -166,6 +166,14 @@ static int setup_guestos(int xc_handle,
            v_start, v_end);
     printf(" ENTRY ADDRESS: %08lx\n", vkern_entry);
 
+    if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) )
+    {
+        printf("Initial guest OS requires too much space\n"
+               "(%luMB is greater than %luMB limit)\n",
+               (v_end-v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
+        goto error_out;
+    }
+
     if ( (pm_handle = init_pfn_mapper((domid_t)dom)) == NULL )
         goto error_out;
 
@@ -541,17 +549,18 @@ static inline int is_loadable_phdr(Elf_Phdr *phdr)
             ((phdr->p_flags & (PF_W|PF_X)) != 0));
 }
 
-static int readelfimage_base_and_size(char *elfbase, 
-                                      unsigned long elfsize,
-                                      unsigned long *pkernstart,
-                                      unsigned long *pkernend,
-                                      unsigned long *pkernentry)
+static int parseelfimage(char *elfbase, 
+                         unsigned long elfsize,
+                         unsigned long *pvirtstart,
+                         unsigned long *pkernstart,
+                         unsigned long *pkernend,
+                         unsigned long *pkernentry)
 {
     Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
     Elf_Phdr *phdr;
     Elf_Shdr *shdr;
     unsigned long kernstart = ~0UL, kernend=0UL;
-    char *shstrtab, *guestinfo;
+    char *shstrtab, *guestinfo, *p;
     int h;
 
     if ( !IS_ELF(*ehdr) )
@@ -588,7 +597,9 @@ static int readelfimage_base_and_size(char *elfbase,
         shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
         if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
             continue;
+
         guestinfo = elfbase + shdr->sh_offset;
+
         if ( (strstr(guestinfo, "GUEST_OS=linux") == NULL) ||
              (strstr(guestinfo, "XEN_VER=1.3") == NULL) )
         {
@@ -596,6 +607,11 @@ static int readelfimage_base_and_size(char *elfbase,
             ERROR("Actually saw: '%s'", guestinfo);
             return -EINVAL;
         }
+
+        *pvirtstart = kernstart;
+        if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
+            *pvirtstart = strtoul(p+10, &p, 0);
+
         break;
     }
     if ( h == ehdr->e_shnum )
index 83eea289aa2232b2d435b675536031fe136e9407..866b4d00162f3575f84e5f67fa89fe25559a725c 100644 (file)
@@ -565,11 +565,17 @@ int construct_dom0(struct domain *p,
      * We'll have to revisit this if we ever support PAE (64GB).
      */
 
-    rc = readelfimage_base_and_size(image_start, image_len,
-                                    &vkern_start, &vkern_end, &vkern_entry);
+    rc = parseelfimage(image_start, image_len, &v_start,
+                       &vkern_start, &vkern_end, &vkern_entry);
     if ( rc != 0 )
         return rc;
 
+    if ( (v_start & (PAGE_SIZE-1)) != 0 )
+    {
+        printk("Initial guest OS must load to a page boundary.\n");
+        return -EINVAL;
+    }
+
     /*
      * Why do we need this? The number of page-table frames depends on the 
      * size of the bootstrap address space. But the size of the address space 
@@ -579,7 +585,6 @@ int construct_dom0(struct domain *p,
      */
     for ( nr_pt_pages = 2; ; nr_pt_pages++ )
     {
-        v_start          = vkern_start & ~((1<<22)-1);
         vinitrd_start    = round_pgup(vkern_end);
         vinitrd_end      = vinitrd_start + initrd_len;
         vphysmap_start   = round_pgup(vinitrd_end);
@@ -593,18 +598,11 @@ int construct_dom0(struct domain *p,
         v_end            = (vstack_end + (1<<22)-1) & ~((1<<22)-1);
         if ( (v_end - vstack_end) < (512 << 10) )
             v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */
-        if ( (((v_end - v_start) >> L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
+        if ( (((v_end - v_start + ((1<<L2_PAGETABLE_SHIFT)-1)) >> 
+               L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
             break;
     }
 
-    if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) )
-    {
-        printk("Initial guest OS requires too much space\n"
-               "(%luMB is greater than %luMB limit)\n",
-               (v_end-v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
-        return -ENOMEM;
-    }
-
     printk("PHYSICAL MEMORY ARRANGEMENT:\n"
            " Kernel image:  %p->%p\n"
            " Initrd image:  %p->%p\n"
@@ -629,6 +627,14 @@ int construct_dom0(struct domain *p,
            v_start, v_end);
     printk(" ENTRY ADDRESS: %08lx\n", vkern_entry);
 
+    if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) )
+    {
+        printk("Initial guest OS requires too much space\n"
+               "(%luMB is greater than %luMB limit)\n",
+               (v_end-v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
+        return -ENOMEM;
+    }
+
     /*
      * Protect the lowest 1GB of memory. We use a temporary mapping there
      * from which we copy the kernel and ramdisk images.
index 72f1617a3245ea77db1eeeb905d1afd7bc9ee491..b59171b5d9550ca3e8ba5652b8284e41b11a4197 100644 (file)
@@ -16,17 +16,18 @@ static inline int is_loadable_phdr(Elf_Phdr *phdr)
             ((phdr->p_flags & (PF_W|PF_X)) != 0));
 }
 
-int readelfimage_base_and_size(char *elfbase, 
-                                      unsigned long elfsize,
-                                      unsigned long *pkernstart,
-                                      unsigned long *pkernend,
-                                      unsigned long *pkernentry)
+int parseelfimage(char *elfbase, 
+                  unsigned long elfsize,
+                  unsigned long *pvirtstart,
+                  unsigned long *pkernstart,
+                  unsigned long *pkernend,
+                  unsigned long *pkernentry)
 {
     Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
     Elf_Phdr *phdr;
     Elf_Shdr *shdr;
     unsigned long kernstart = ~0UL, kernend=0UL;
-    char *shstrtab, *guestinfo;
+    char *shstrtab, *guestinfo, *p;
     int h;
 
     if ( !IS_ELF(*ehdr) )
@@ -63,14 +64,21 @@ int readelfimage_base_and_size(char *elfbase,
         shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
         if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
             continue;
+
         guestinfo = elfbase + shdr->sh_offset;
         printk("Xen-ELF header found: '%s'\n", guestinfo);
+
         if ( (strstr(guestinfo, "GUEST_OS=linux") == NULL) ||
              (strstr(guestinfo, "XEN_VER=1.3") == NULL) )
         {
             printk("ERROR: Xen will only load Linux built for Xen v1.3\n");
             return -EINVAL;
         }
+
+        *pvirtstart = kernstart;
+        if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
+            *pvirtstart = simple_strtoul(p+10, &p, 0);
+
         break;
     }
     if ( h == ehdr->e_shnum )
index c66aeb0d3dc33da5684433b6ef02433af770b913..2abd8a2206251214bac6da57af460a57e02931da 100644 (file)
@@ -525,7 +525,8 @@ typedef struct {
 #endif
 
 extern int loadelfimage(char *);
-extern int readelfimage_base_and_size(
-    char *, unsigned long, unsigned long *, unsigned long *, unsigned long *);
+extern int parseelfimage(
+    char *, unsigned long, unsigned long *,
+    unsigned long *, unsigned long *, unsigned long *);
 
 #endif /* __XEN_ELF_H__ */